home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Pascal Super Library
/
Pascal Super Library (CW International)(1997).bin
/
PGM_TOOL
/
PARAMS
/
CMDLINE.PAS
next >
Wrap
Pascal/Delphi Source File
|
1994-12-09
|
13KB
|
458 lines
unit CmdLine;
{*******************************************************}
{ }
{ Copyright 1992, 1994 by James M. Clark. }
{ }
{ OOP version of Params unit }
{ }
{ Handles command-line parameters; }
{ can also set default options. }
{ See also: skel.pas, pardemo.pas, }
{ config.exe, config.doc }
{ }
{*******************************************************}
interface
uses Dos, Objects;
type
PCmdLine = ^TCmdLine;
TCmdLine = object(TObject)
Option: string[3]; {e.g., the '/c' in '/c12'}
OptChr: char; {e.g., the 'c' in '/c12'}
OptStr: string; {e.g., the '12' in '/c12'}
Dir: DirStr; {full pathname of directory}
SRec: SearchRec; {full details}
ParNo: integer; {number of current parameter}
FileNo: word; {number of current file}
FPars: word; {number of expanded parameters}
MayExpand: boolean; {enables filename expansion}
AttrMask: word; {file types to find}
constructor Init(Expand: boolean);
procedure AppDone; virtual;
procedure ChkFlg;
procedure DoFile(FName: PathStr; Expdd: boolean);
virtual; {abstract}
function ExtendOpt: ExtStr;
function GetBool: boolean;
function GetInt: integer;
procedure ParseOpts(ParStr: string);
procedure RptError(Complaint, Name: string;
Dispose: char); virtual;
procedure ScanPars;
procedure SetOpt; virtual; {abstract}
procedure ShowUsage; virtual; {abstract}
end;
{-------------------------------------------------------}
{ globals }
{ExeDir: Get directory of program file if possible, else '':}
function ExeDir: DirStr;
{ExeName: Get name of program file if possible, else '':}
function ExeName: NameStr;
{GetDefaults: get default option string:}
{strips any trailing '/' (padding) characters}
function GetDefaults(DefOpts: string): string;
{StripPadding: strip any trailing '/' (padding) characters:}
function StripPadding(Opts: string): string;
{*******************************************************}
implementation
const
{error messages; used with RptError procedure:}
sCantFind = 'Can not find file(s)';
sBadBool = 'Option value should be ''+'' or ''-''';
sBadInt = 'Option value should be an integer';
sBadFlag = 'Extra characters after option';
{corresponding disposal modes; used with RptError procedure:}
dCantFind: char = 'i'; {used by ScanPars}
dBadBool: char = 'u'; {used by GetBool}
dBadInt: char = 'u'; {used by GetInt}
dBadFlag: char = 'u'; {used by ChkFlg}
Copyright = 'CmdLine.tpu (C) 12-09-94 J. M. Clark';
{*******************************************************}
{ TCmdLine }
constructor TCmdLine.Init(Expand: boolean);
begin
inherited Init;
ParNo:= -1; {number of current parameter}
FileNo:= 0; {number of current file}
FPars:= 0; {number of expanded parameters}
MayExpand:= Expand; {enables filename expansion}
AttrMask:= AnyFile-Directory-VolumeID; {file types to find}
end; {TCmdLine.Init}
{-------------------------------------------------------}
{AppDone: prepare to exit from the application:}
procedure TCmdLine.AppDone;
begin
{do anything needed for an orderly exit}
{.. but don't halt}
end; {TCmdLine.AppDone}
{----------------------------------------------------------}
{ChkFlg: check if extra characters after a simple flag:}
{for example, /fxy when /f was expected}
procedure TCmdLine.ChkFlg;
begin
if OptStr <> '' then RptError(sBadFlag, Option, dBadFlag);
end; {TCmdLine.ChkFlg}
{-------------------------------------------------------}
{DoFile: process the file (or name) FName:}
{
If Expdd = true, FName is expanded name of file found in Dir,
and global variables Path, Dir, and SRec may be used;
else, FName is just the ParStr, and not necessarily a filename.
Use "IsFile" to count FName as a file.
}
procedure TCmdLine.DoFile(FName: PathStr; Expdd: boolean); {over-ride}
begin
Abstract;
end; {TCmdLine.DoFile}
{ outline of method to override }
(***
procedure IsFile;
begin
if not Expdd then begin
inc(FileNo); inc(FPars);
end;
end;
begin {DoFile}
{process file here according to options}
end;
***)
{-------------------------------------------------------}
{ExtendOpt: Extend the option name (OptChr) by taking one}
{character from the option value (OptStr) if available: }
{If OptStr is '', then append '/' to OptChr instead. }
function TCmdLine.ExtendOpt: ExtStr;
begin
if Length(OptStr) > 0 then begin
Option:= Option + OptStr[1];
ExtendOpt:= OptChr + OptStr[1];
Delete(OptStr, 1, 1);
end else begin
ExtendOpt:= OptChr + '/'; {converts char to string}
end;
end; {TCmdLine.ExtendOpt}
{-------------------------------------------------------}
{GetBool: convert option string OptStr to a boolean value:}
function TCmdLine.GetBool: boolean;
begin
if (OptStr = '') or (OptStr = '+') then GetBool:= true
else if OptStr = '-' then GetBool:= false
else RptError(sBadBool, Option, dBadBool);
end; {TCmdLine.GetBool}
{-------------------------------------------------------}
{GetInt: convert option string OptStr to an integer value:}
function TCmdLine.GetInt: integer;
var
int, err: integer;
begin
Val(OptStr, int, err);
if err = 0 then GetInt:= int
else RptError(sBadInt, Option, dBadInt);
end; {TCmdLine.GetInt}
{-------------------------------------------------------}
{ParseOpts: scan parameter string ParStr and collect option data:}
{options start with '/' and may run together, e.g.: /b+/c12/d-/eString }
{or may be separated by spaces, e.g.: /b+ /c12 /d- /eString }
{uses PSetOpt to define the options}
procedure TCmdLine.ParseOpts(ParStr: string);
var
ChrPos: integer; {search position in ParStr}
begin
{we begin with the assumption that ParStr[1] = '/'}
while Length(ParStr) > 1 do begin {quit if ParStr end is '/'}
OptChr:= ParStr[2];
if OptChr = '/' then exit; {quit if '//' is found}
Option:= '/'+OptChr;
{delete the '/' and OptChr from ParStr:}
Delete(ParStr, 1, 2);
ChrPos:= Pos(' ', ParStr); {look for a space, else..}
if ChrPos = 0
then ChrPos:= Pos('/', ParStr); {look for another '/'}
{if no more '/', then OptStr is all remaining of ParStr:}
if ChrPos = 0 then begin
OptStr:= ParStr;
SetOpt; {interpret OptChr and OptStr}
exit;
end else begin
OptStr:= Copy(ParStr, 1, ChrPos-1);
SetOpt; {interpret OptChr and OptStr}
Delete(ParStr, 1, ChrPos-1);
{now the next space or '/' is in ParStr[1]}
ChrPos:= Pos('/', ParStr); {look for next '/'}
while (Length(ParStr) > 2) and (ParStr[1] = ' ')
and ((ParStr[2] = '/') or (ParStr[2] = ' '))
do Delete(ParStr, 1, 1);
end;
end; {while}
end; {TCmdLine.ParseOpts}
{-------------------------------------------------------}
{RptError: display error message, and halt/explain/ignore:}
{example: Can not find file(s): "yourfile.ext". }
{Dispose is 'i', 'u', or 'h': see below:}
procedure TCmdLine.RptError(Complaint, Name: string; Dispose: char);
begin
if (Dispose = 'u') or (Dispose = 'h') then AppDone;
write(Complaint, ': "', Name, '".');
case Dispose of
'i': {Ignore} begin
writeln(' (ignored)');
exit;
end;
'u': {show Usage & halt} begin
writeln;
ShowUsage;
Halt;
end;
'h': {Halt} begin
writeln;
Halt;
end;
end;
writeln; {ignore without saying so}
end; {TCmdLine.RptError}
{-------------------------------------------------------}
{ScanPars: scan the command line, process according to syntax:}
{ Parameters starting with '/' are processed by ParseOpts. }
{ Parameters with '*' or '?' are expanded per DOS convention }
{ (by directory search) to possibly more than one file and }
{ processed by DoFile( , true) if MayExpand is true. }
{ Other parameters are processed by DoFile( , false); these }
{ may or may not be filenames. }
procedure TCmdLine.ScanPars;
var
EFiles: word;
PN: word;
ParStr: string;
ChrPos: integer;
Path: PathStr; {expanded pathname, may have wildcards}
{Path = Dir + Name + Ext}
Name: NameStr; {may have wildcards}
Ext: ExtStr; {may have wildcards, includes '.'}
begin
FileNo:= 0;
FPars:= 0;
for PN:= 1 to ParamCount do begin
ParNo:= PN;
ParStr:= ParamStr(PN);
if ParStr[1] = '/' then ParseOpts(ParStr)
else begin
if MayExpand and
((Pos('*',ParStr) > 0) or (Pos('?',ParStr) > 0))
then begin
EFiles:= 0;
inc(FPars); {count filename parameters}
Path:= FExpand(ParStr);
FSplit(Path, Dir, Name, Ext);
{search the directory:}
FindFirst(Path, AttrMask, SRec);
while DosError = 0 do begin
inc(FileNo); {count all files}
inc(EFiles); {count exanded files for each ParStr}
DoFile(Dir + Srec.Name, true);
FindNext(SRec);
end;
if EFiles = 0 then RptError(sCantFind, Path, dCantFind);
end else begin
{ParStr is not necessarily a filename:}
{DoFile may or may not inc FPars and FileNo:}
DoFile(ParStr, false);
end;
end; {if '/'}
end; {for}
end; {TCmdLine.ScanPars}
{-------------------------------------------------------}
{SetOpt: set the option named OptChr to the value given by OptStr:}
{ Uses GetBool for booleans; e.g., /a+ /b /c- : a,b true, c false }
{ Uses GetInt for integers; e.g., /a-16 /b23 : sets a= -16, b= 23 }
{ String values are direct; e.g., /fSomeName : sets f= 'SomeName' }
procedure TCmdLine.SetOpt;
begin
Abstract;
end; {TCmdLine.SetOpt}
{ If SetOpt uses OptChr to define options: }
{ Option is the '/c' in '/c12' }
{ OptChr:is the 'c' in '/c12' }
{ OptStr:is the '12' in '/c12' }
{ If SetOpt uses Optn:= ExtendOpt to define options: }
{ Option is the '/co' in '/co12' or '/c' in '/c' }
{ Optn is the 'co' in '/co12' or 'c' in '/c' }
{ OptStr is the '12' in '/co12' or '' in '/c' }
{ outline of method to override }
(***
{
to use 2-char Optn instead of OptChr:
Optn:= ExtendOpt;
.. and use 2-level case:
case Optn[1] of ..
case Optn[2] of ..
}
case OptChr of
{process options here}
{use "if ParNo < 0" for initial-only options}
{examples:}
'b': BFlag:= GetBool;
'i': IValue:= GetInt;
's': StringVal:= OptStr;
'?': begin
PAppDone;
ShowUsage;
Halt;
end;
{none of the above:}
else RptError('Undefined option', Option, 'u');
end;
***)
{-------------------------------------------------------}
{ShowUsage: explain command-line parameters and options:}
procedure TCmdLine.ShowUsage;
begin
Abstract;
end; {TCmdLine.ShowUsage}
{ outline of method to override }
(***
writeln(Copyright);
writeln('Usage:');
{explain parameters & options here}
writeln('Default options are: ', GetDefaults(Config.data));
***)
{*******************************************************}
{ExeDir: Get directory of program file if possible, else '':}
function ExeDir: DirStr;
var
Dir: DirStr;
Name: NameStr;
Ext: ExtStr;
begin
If Lo(DosVersion) >= 3 then begin
FSplit(ParamStr(0), Dir, Name, Ext);
ExeDir:= Dir;
end else ExeDir:= '';
end; {ExeDir}
{-------------------------------------------------------}
{ExeName: Get name of program file if possible, else '':}
function ExeName: NameStr;
var
Dir: DirStr;
Name: NameStr;
Ext: ExtStr;
begin
If Lo(DosVersion) >= 3 then begin
FSplit(ParamStr(0), Dir, Name, Ext);
ExeName:= Name;
end else ExeName:= '';
end; {ExeName}
{-------------------------------------------------------}
{GetDefaults: get default option string:}
{strips any trailing '/' (padding) characters}
function GetDefaults(DefOpts: string): string;
var
ChrPos: integer;
begin
ChrPos:= Pos('//', DefOpts) - 1;
if ChrPos < 0 then begin
ChrPos:= Length(DefOpts);
if DefOpts[ChrPos] = '/' then dec(ChrPos);
end;
GetDefaults:= Copy(DefOpts, 1, ChrPos);
end; {GetDefaults}
{-------------------------------------------------------}
{StripPadding: strip any trailing '/' (padding) characters:}
function StripPadding(Opts: string): string;
var
ChrPos: integer;
begin
ChrPos:= Pos('//', Opts) - 1;
if ChrPos < 0 then begin
ChrPos:= Length(Opts);
if Opts[ChrPos] = '/' then dec(ChrPos);
end;
StripPadding:= Copy(Opts, 1, ChrPos);
end; {StripPadding}
end.